﻿#include "gradient.h"
#include "utils.h"

//计算gradient
int gradientprocess(matrix inimg, matrix outbuf, int mflag)
{
	if (inimg.data == NULL || inimg.w == 0) {
		cout << "image empty!" << endl;
		return FALSE;
	}
	//uchar* pgray=NULL;
	matrix pgray,edgemap;

	memcpy(&pgray, &inimg, sizeof(matrix));
	memcpy(&edgemap, &inimg, sizeof(matrix));
	edgemap.channel = pgray.channel = 1;
	if (inimg.channel > 1) {
		cout << "input is not gray image!" << endl;
		pgray.data = GetGrayimg0(inimg);
		//return FALSE;
	}
	else {
		pgray.data = inimg.data;
	}
	edgemap.data = NULL;
	edgemap.data = (uchar*)malloc(sizeof(uchar) * edgemap.w * edgemap.h);
	if (edgemap.data == NULL) {
		cout << "can not malloc memory to edgemap" << endl;
		return FALSE;
	}
	memset(edgemap.data, 0, edgemap.w * edgemap.h);

	int kw, kh;
	switch (mflag)
	{
	case GRADIENT_9X9:
		kw = kh = 9;
		break;

	case GRADIENT_7X7:
		kw = kh = 7;
		break;

	case GRADIENT_3X3:
		kw = kh = 3;
		break;

	default:
		return FALSE;
	}
	int skw, skh, row = inimg.h, col = inimg.w, r, c,sr,sc, pds,x,y;
	skw = skh = (kw + 1) >> 1;	//sub kernel width
	pds = (kw - 1) >> 1;		//padding size
	int dx, dy, d,s1,s2,s3,s4;
	uchar* pimg = inimg.data,*pout = edgemap.data;
	for (r = 0; r < row; r++) {
		for (c = 0; c < col; c++) {
			if (r - pds < 0 || r + pds >= row || c - pds < 0 || c + pds >= col) {
				*pout = 0;
				pout++;
				continue;
			}
			s1 = s2 = s3 = s4 = 0;
			for (sr = 0; sr < skh; sr++) {
				for (sc = 0; sc < skw; sc++) {
					y = r - sr;
					x = c - sc;
					s1 += pgray.data[y * inimg.w + x];
					y = r - sr;
					x = c + sc;
					s2 += pgray.data[y * inimg.w + x];
					y = r + sr;
					x = c - sc;
					s3 += pgray.data[y * inimg.w + x];
					y = r + sr;
					x = c + sc;
					s4 += pgray.data[y * inimg.w + x];
				}
			}
			dx = ((s2 - s1 + s4 - s3) / (skh * skw)) >> 1;
			dy = ((s3 - s1 + s4 - s2) / (skh * skw)) >> 1;
			//int e = (int)(sqrt(dx * dx + dy * dy));
			d = (uchar)clip((int)(sqrt(dx * dx + dy * dy)), 0, 255);
			*pout = d;
			pout++;
		}
	}

	writeMat(edgemap, "mark/gradient-map.ppm", PPM_P6_OUT);
	if (inimg.channel > 1) {
		free(pgray.data);
	}
	//memcpy(outbuf.data, edgemap.data,sizeof(edgemap.w* edgemap.h));
	//outbuf.channel = 1;
	free(edgemap.data);
    return OK;
}

int gradientavgprocess(matrix inimg, matrix outbuf, int mflag)
{
	if (inimg.data == NULL || inimg.w == 0) {
		cout << "image empty!" << endl;
		return FALSE;
	}
	//uchar* pgray=NULL;
	matrix pgray, edgemap;

	memcpy(&pgray, &inimg, sizeof(matrix));
	memcpy(&edgemap, &inimg, sizeof(matrix));
	edgemap.channel = pgray.channel = 1;
	if (inimg.channel > 1) {
		cout << "input is not gray image!" << endl;
		pgray.data = GetGrayimg0(inimg);
		//return FALSE;
	}
	else {
		pgray.data = inimg.data;
	}
	edgemap.data = NULL;
	edgemap.data = (uchar*)malloc(sizeof(uchar) * edgemap.w * edgemap.h);
	if (edgemap.data == NULL) {
		cout << "can not malloc memory to edgemap" << endl;
		return FALSE;
	}
	memset(edgemap.data, 0, edgemap.w * edgemap.h);

	int kw, kh, skw, skh;
	switch (mflag)
	{
	case GRADIENT_AVG_7X7:
		kw = kh = 7;
		skw = skh = 3;
		break;

	case GRADIENT_AVG_3X3:
		kw = kh = 3;
		skw = skh = 1;
		break;

	default:
		return FALSE;
	}
	int row = inimg.h, col = inimg.w, r, c, sr, sc, pds, x, y;
	//skw = skh = (kw + 1) >> 1;	//sub kernel width
	pds = (kw - 1) >> 1;		//padding size
	int dx, dy, d, s1, s2, s3, s4, s5, s6, s7, s8, s9,d1,d2,d3,d4;
	uchar* pimg = inimg.data, * pout = edgemap.data;
	for (r = 0; r < row; r++) {
		for (c = 0; c < col; c++) {
			if (r - pds < 0 || r + pds >= row || c - pds < 0 || c + pds >= col) {
				*pout = 0;
				pout++;
				continue;
			}
			s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = 0;
			for (sr = 0; sr < skh; sr++) {
				for (sc = 0; sc < skw; sc++) {
					y = r - sr - 1;
					x = c - sc - 1;
					s1 += pgray.data[y * inimg.w + x];
					y = r - sr - 1;
					x = c + sc - ((skw - 1) >> 1);
					s2 += pgray.data[y * inimg.w + x];
					y = r - sr - 1;
					x = c + sc + ((skw - 1) >> 1);
					s3 += pgray.data[y * inimg.w + x];
					y = r + sr - ((skh - 1) >> 1);
					x = c - sc - 1;
					s4 += pgray.data[y * inimg.w + x];
					y = r + sr - ((skh - 1) >> 1);
					x = c + sc - ((skw - 1) >> 1);
					s5 += pgray.data[y * inimg.w + x];
					y = r + sr - ((skh - 1) >> 1);
					x = c + sc + 1;
					s6 += pgray.data[y * inimg.w + x];
					y = r + sr + 1;
					x = c - sc - 1;
					s7 += pgray.data[y * inimg.w + x];
					y = r + sr + 1;
					x = c + sc - ((skw - 1) >> 1);
					s8 += pgray.data[y * inimg.w + x];
					y = r + sr + 1;
					x = c + sc + 1;
					s9 += pgray.data[y * inimg.w + x];
				}
			}
			d1 = (int)abs((s2 - s1 + s5 - s4 + s4 - s1 + s5 - s2) / (skw * skh));
			d2 = (int)abs((s3 - s2 + s6 - s5 + s5 - s2 + s6 - s3) / (skw * skh));
			d3 = (int)abs((s5 - s4 + s7 - s8 + s7 - s4 + s8 - s5) / (skw * skh));
			d4 = (int)abs((s6 - s5 + s9 - s8 + s8 - s5 + s9 - s6) / (skw * skh));

			d = (d1+d2+d3+d4) >> 2;
			if (d > 255 || d < 0) {
				cout << "out of range(0,255):" << d << endl;
			}
			//dy = ((s3 - s1 + s4 - s2) / (skh * skw)) >> 1;
			////int e = (int)(sqrt(dx * dx + dy * dy));
			//d = (uchar)clip((int)(sqrt(dx * dx + dy * dy)), 0, 255);
			*pout = clip(d,0,255);
			pout++;
		}
	}

	writeMat(edgemap, "mark/gradient-avg-map.ppm", PPM_P6_OUT);
	if (inimg.channel > 1) {
		free(pgray.data);
	}
	//memcpy(outbuf.data, edgemap.data,sizeof(edgemap.w* edgemap.h));
	//outbuf.channel = 1;
	free(edgemap.data);
	return OK;
}
